using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;
using System.Xml.Serialization;
using System.Configuration;

namespace NBear.Web.Modules
{
    public class UrlRewriteModule : IHttpModule
    {
        private static RulesEngine rulesEngine = null;

        #region IHttpModule Members

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
        }

        private void context_BeginRequest(object sender, EventArgs e)
        {
            if (rulesEngine == null)
            {
                rulesEngine = new RulesEngine();
            }
            rulesEngine.Execute(((HttpApplication)sender).Context);
        }

        #endregion
    }

    public class RulesEngine
    {
        #region Private Members

        private Dictionary<string, string> rules = new Dictionary<string, string>();

        private static string GetPath(HttpContext context)
        {
            return context.Request.Path + "?" + context.Request.QueryString;
        }

        #endregion

        #region Constructors

        public RulesEngine()
        {
            //load up rules from web.config
            object section = ConfigurationManager.GetSection("UrlRewriteRules");

            if (typeof(System.Xml.XmlNodeList).IsAssignableFrom(section.GetType()))
            {
                section = new UrlRewriteRules().Create(null, null, ((System.Xml.XmlNodeList)section)[0]);
            }

            UrlRewriteRules.Rule[] rs = (UrlRewriteRules.Rule[])section;

            if (rs != null)
            {
                foreach (UrlRewriteRules.Rule rule in rs)
                {
                    rules.Add(rule.key, rule.value);
                }
            }
        }

        #endregion

        #region Public Members

        public void Execute(HttpContext context)
        {
            string srcUrl = GetPath(context).TrimEnd('?').ToLower();
            string targetUrl = srcUrl;
            foreach (string key in rules.Keys)
            {
                targetUrl = new Regex(key, RegexOptions.IgnoreCase).Replace(targetUrl, rules[key], 1);
            }
            if (!targetUrl.Equals(srcUrl))
            {
                string queryStr = context.Request.ServerVariables["QUERY_STRING"];
                string[] splitTargetUrl = targetUrl.Split('?');
                if (splitTargetUrl.Length > 1)
                {
                    queryStr = splitTargetUrl[1] + queryStr;
                }
                context.RewritePath(splitTargetUrl[0], null, queryStr);
            }
        }

        #endregion
    }

    public class UrlRewriteRules : System.Configuration.IConfigurationSectionHandler
    {
        public struct Rule
        {
            public string key;
            public string value;
        }

        private Rule[] rules;

        #region IConfigurationSectionHandler Members

        public object Create(object parent, object configContext, XmlNode section)
        {
            XmlNodeList ruleNodes = section.SelectNodes("Rule");
            if (ruleNodes != null && ruleNodes.Count > 0)
            {
                rules = new Rule[ruleNodes.Count];
                for (int i = 0; i < ruleNodes.Count; i++)
                {
                    Rule newRule = new Rule();
                    newRule.key = ruleNodes[i].Attributes["key"].InnerXml;
                    newRule.value = ruleNodes[i].Attributes["value"].InnerXml;
                    rules[i] = newRule;
                }
            }
            return rules;
        }

        #endregion
    }
}
